# ifndef __MiniGDIPlus_H_
# define __MiniGDIPlus_H_

// This is small excerpt from GDI+ official header files available in MS Platform SDK.

//# include <GdiPlusFlat.h>

typedef enum {
    Ok = 0,
    GenericError = 1,
    InvalidParameter = 2,
    OutOfMemory = 3,
    ObjectBusy = 4,
    InsufficientBuffer = 5,
    NotImplemented = 6,
    Win32Error = 7,
    WrongState = 8,
    Aborted = 9,
    FileNotFound = 10,
    ValueOverflow = 11,
    AccessDenied = 12,
    UnknownImageFormat = 13,
    FontFamilyNotFound = 14,
    FontStyleNotFound = 15,
    NotTrueTypeFont = 16,
    UnsupportedGdiplusVersion = 17,
    GdiplusNotInitialized = 18,
    PropertyNotFound = 19,
    PropertyNotSupported = 20
} Status;

class GpGraphics {};
class GpImage {};

/////////////////////////////////////////////////

enum DebugEventLevel
{
    DebugEventLevelFatal,
    DebugEventLevelWarning
};

// Callback function that GDI+ can call, on debug builds, for assertions
// and warnings.

typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);

// Notification functions which the user must call appropriately if
// "SuppressBackgroundThread" (below) is set.

typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);

// Input structure for GdiplusStartup()

struct GdiplusStartupInput
{
    UINT32 GdiplusVersion;             // Must be 1
    DebugEventProc DebugEventCallback; // Ignored on free builds
    BOOL SuppressBackgroundThread;     // FALSE unless you're prepared to call 
                                       // the hook/unhook functions properly
    BOOL SuppressExternalCodecs;       // FALSE unless you want GDI+ only to use
                                       // its internal image codecs.
    
    GdiplusStartupInput(
        DebugEventProc debugEventCallback = NULL,
        BOOL suppressBackgroundThread = FALSE,
        BOOL suppressExternalCodecs = FALSE)
    {
        GdiplusVersion = 1;
        DebugEventCallback = debugEventCallback;
        SuppressBackgroundThread = suppressBackgroundThread;
        SuppressExternalCodecs = suppressExternalCodecs;
    }
};

// Output structure for GdiplusStartup()

struct GdiplusStartupOutput
{
    // The following 2 fields are NULL if SuppressBackgroundThread is FALSE.
    // Otherwise, they are functions which must be called appropriately to
    // replace the background thread.
    //
    // These should be called on the application's main message loop - i.e.
    // a message loop which is active for the lifetime of GDI+.
    // "NotificationHook" should be called before starting the loop,
    // and "NotificationUnhook" should be called after the loop ends.
    
    NotificationHookProc NotificationHook;
    NotificationUnhookProc NotificationUnhook;
};

// GDI+ initialization. Must not be called from DllMain - can cause deadlock.
//
// Must be called before GDI+ API's or constructors are used.
//
// token  - may not be NULL - accepts a token to be passed in the corresponding
//          GdiplusShutdown call.
// input  - may not be NULL
// output - may be NULL only if input->SuppressBackgroundThread is FALSE.

extern "C" Status WINAPI GdiplusStartup(
    OUT ULONG_PTR *token,
    const GdiplusStartupInput *input,
    OUT GdiplusStartupOutput *output);

// GDI+ termination. Must be called before GDI+ is unloaded. 
// Must not be called from DllMain - can cause deadlock.
//
// GDI+ API's may not be called after GdiplusShutdown. Pay careful attention
// to GDI+ object destructors.

extern "C" VOID WINAPI GdiplusShutdown(ULONG_PTR token);

/////////////////////////////////////////////////////////////

typedef DWORD GpStatus;

#define WINGDIPAPI __stdcall
#define GDIPCONST const

GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics);
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics);
GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename, GpImage **image);
GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image);

GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width);
GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height);

GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, INT x, INT y, INT width, INT height);

enum Unit
{
    UnitWorld,      // 0 -- World coordinate (non-physical unit)
    UnitDisplay,    // 1 -- Variable -- for PageTransform only
    UnitPixel,      // 2 -- Each unit is one device pixel.
    UnitPoint,      // 3 -- Each unit is a printer's point, or 1/72 inch.
    UnitInch,       // 4 -- Each unit is 1 inch.
    UnitDocument,   // 5 -- Each unit is 1/300 inch.
    UnitMillimeter  // 6 -- Each unit is 1 millimeter.
};

typedef Unit GpUnit;

class GpImageAttributes {};

typedef BOOL (CALLBACK * ImageAbort)(VOID *);
typedef ImageAbort DrawImageAbort;

GpStatus WINGDIPAPI GdipDrawImageRectRectI(
	GpGraphics *graphics, GpImage *image,
	INT dstx, INT dsty, INT dstwidth, INT dstheight,
	INT srcx, INT srcy, INT srcwidth, INT srcheight,
	GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData
);

//--------------------------------------------------------------------------
// ImageCodecInfo structure
//--------------------------------------------------------------------------

class ImageCodecInfo
{
public:          
    CLSID Clsid;
    GUID  FormatID;
    const WCHAR* CodecName;
    const WCHAR* DllName;
    const WCHAR* FormatDescription;
    const WCHAR* FilenameExtension;
    const WCHAR* MimeType;
    DWORD Flags;
    DWORD Version;
    DWORD SigCount;
    DWORD SigSize;
    const BYTE* SigPattern;
    const BYTE* SigMask;
};
//////////////////////////////////////////////////

typedef Status (WINAPI * pfGdiplusStartup_t) (OUT ULONG_PTR *token, const GdiplusStartupInput *input, OUT GdiplusStartupOutput *output);
extern pfGdiplusStartup_t g_pfGdiplusStartup;

typedef VOID (WINAPI * pfGdiplusShutdown_t) (ULONG_PTR token);
extern pfGdiplusShutdown_t g_pfGdiplusShutdown;

typedef GpStatus (WINGDIPAPI * pfGdipCreateFromHDC_t) (HDC hdc, GpGraphics **graphics);
extern pfGdipCreateFromHDC_t g_pfGdipCreateFromHDC;

typedef GpStatus (WINGDIPAPI * pfGdipDeleteGraphics_t) (GpGraphics *graphics);
extern pfGdipDeleteGraphics_t g_pfGdipDeleteGraphics;

typedef GpStatus (WINGDIPAPI * pfGdipLoadImageFromFile_t) (GDIPCONST WCHAR* filename, GpImage **image);
extern pfGdipLoadImageFromFile_t g_pfGdipLoadImageFromFile;

typedef GpStatus (WINGDIPAPI * pfGdipDisposeImage_t) (GpImage *image);
extern pfGdipDisposeImage_t g_pfGdipDisposeImage;

typedef GpStatus (WINGDIPAPI * pfGdipGetImageWidth_t) (GpImage *image, UINT *width);
extern pfGdipGetImageWidth_t g_pfGdipGetImageWidth;

typedef GpStatus (WINGDIPAPI * pfGdipGetImageHeight_t) (GpImage *image, UINT *height);
extern pfGdipGetImageHeight_t g_pfGdipGetImageHeight;

typedef GpStatus (WINGDIPAPI * pfGdipDrawImageRectRectI_t) (
	GpGraphics *graphics, GpImage *image,
	INT dstx, INT dsty, INT dstwidth, INT dstheight,
	INT srcx, INT srcy, INT srcwidth, INT srcheight,
	GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData
);
extern pfGdipDrawImageRectRectI_t g_pfGdipDrawImageRectRectI;

typedef GpStatus (WINGDIPAPI * pfGdipGetImageDecodersSize_t) (UINT *numDecoders, UINT *size);
extern pfGdipGetImageDecodersSize_t g_pfGdipGetImageDecodersSize;

typedef GpStatus (WINGDIPAPI * pfGdipGetImageDecoders_t) (UINT numDecoders, UINT size, ImageCodecInfo *decoders);
extern pfGdipGetImageDecoders_t g_pfGdipGetImageDecoders;

typedef GpStatus (WINGDIPAPI * pfGdipGetImageGraphicsContext_t) (GpImage *image, GpGraphics **graphics);
extern pfGdipGetImageGraphicsContext_t g_pfGdipGetImageGraphicsContext;

//GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics (INT width, INT height, GpGraphics* target, GpBitmap** bitmap);

//////////////////////////////////

bool InitGdiPlus ();

class CGdipGraphics {
  public:
	CGdipGraphics (HDC _hDC) :
		m_pGraphics (NULL)
	{
		g_pfGdipCreateFromHDC (_hDC, & m_pGraphics);
	}
	~CGdipGraphics () {
		if (m_pGraphics)
			g_pfGdipDeleteGraphics (m_pGraphics);
	}

	operator GpGraphics * () const {return m_pGraphics;}

  private:
	GpGraphics * m_pGraphics;
};

class CGdipImage {
  public:
	CGdipImage () : pImage (NULL) {}
	~CGdipImage () {
		if (pImage)
			g_pfGdipDisposeImage (pImage);
	}

	GpStatus LoadImageFromFile (const wchar_t * _strFileName) {
		assert (pImage == NULL);
		return g_pfGdipLoadImageFromFile (_strFileName, & pImage);
	}

	UINT Width () const {
		UINT uWidth = 0;
		g_pfGdipGetImageWidth  (pImage, & uWidth);
		return uWidth;
	}
	UINT Height () const {
		UINT uHeight = 0;
		g_pfGdipGetImageHeight (pImage, & uHeight);
		return uHeight;
	}

	operator GpImage * () const {return pImage;}

  private:
	GpImage * pImage;
};

# endif // __MiniGDIPlus_H_